﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Granite.Modeling;
using System.Runtime.Serialization;
using Granite.DataAnnotations;
using System.Xml.Linq;

namespace Rifts.Models.Characters
{

	[DataContract]
	public class UnarmedAttack : ChangeTrackingModelBase
	{

		public UnarmedAttack() { }

		public static UnarmedAttack Parse(XElement node)
		{
			var abilityName = node.GetAttribute("Name");
			var basedOn = node.GetAttribute("BasedOn");
			var damageBase = node.GetAttribute("Damage");
			var weaponType = node.GetEnum<WeaponType>("Type", WeaponType.Melee);
			var damageType = node.GetEnum2<DamageType>("DamageType");
			var ammo = node.GetAttribute("Ammo");
			var range = node.GetAttribute("Range");
			var notes = node.GetAttribute("Notes");

			return new UnarmedAttack(abilityName, basedOn, damageBase, weaponType, damageType, ammo, range, notes);
		}

		public UnarmedAttack(string name, string basedOn, string damageBase, WeaponType weaponType, DamageType? damageType, string ammo, string range, string notes)
		{
			Name = name;
			BasedOn = basedOn;
			DamageBase = damageBase;
			WeaponType = weaponType;
			OverrideDamageType = damageType;
			Ammo = ammo;
			Range = range;
			Notes = notes;
		}

		[DataMember]
		public string Name
		{
			get { return Get<String>("Name"); }
			set { Set(value, "Name"); }
		}

		[DataMember]
		public string BasedOn
		{
			get { return Get<String>("BasedOn"); }
			set { Set(value, "BasedOn"); }
		}

		[DataMember]
		public WeaponType WeaponType
		{
			get { return Get<WeaponType>("WeaponType"); }
			set { Set(value, "WeaponType"); }
		}

		[DataMember]
		public DamageType? OverrideDamageType
		{
			get { return Get<DamageType?>("OverrideDamageType"); }
			set { Set(value, "OverrideDamageType"); }
		}

		[DataMember]
		public string Ammo
		{
			get { return Get<string>("Ammo"); }
			set { Set(value, "Ammo"); }
		}

		[DataMember]
		public string Range
		{
			get { return Get<string>("Range"); }
			set { Set(value, "Range"); }
		}

		[DataMember]
		public string Notes
		{
			get { return Get<string>("Notes"); }
			set { Set(value, "Notes"); }
		}

		/// <summary>
		/// The DamageBase is added to all attacks. It is used to represent claws
		/// </summary>
		[DataMember]
		public string DamageBase
		{
			get { return Get<String>("DamageBase"); }
			set { Set(value, "DamageBase"); }
		}


		public UnarmedAttack Clone()
		{
			return new UnarmedAttack(Name, BasedOn, DamageBase, WeaponType, OverrideDamageType, Ammo, Range, Notes);
		}

		/// <summary>
		/// This comes from the character itself
		/// </summary>
		public int? StrikeBase
		{
			get { return Get<int?>("StrikeBase"); }
			set { Set(value, "StrikeBase"); }
		}

		[CalculatedField("StrikeBase")]
		public int? Strike
		{
			get { return StrikeBase; }
		}



		/// <summary>
		/// This is calculated from PS/PS Type based on the type of attack
		/// </summary>
		public string RestrainedDamageBase
		{
			get { return Get<String>("RestrainedDamageBase"); }
			private set { Set(value, "RestrainedDamageBase"); }
		}

		/// <summary>
		/// This is calculated from PS/PS Type based on the type of attack
		/// </summary>
		public DamageType RestrainedDamageType
		{
			get { return Get<DamageType>(DamageType.SD, "RestrainedDamageType"); }
			private set { Set(value, "RestrainedDamageType"); }
		}

		/// <summary>
		/// This is calculated from PS/PS Type based on the type of attack
		/// </summary>
		public string NormalDamageBase
		{
			get { return Get<String>("NormalDamageBase"); }
			private set { Set(value, "NormalDamageBase"); }
		}

		/// <summary>
		/// This is calculated from PS/PS Type based on the type of attack
		/// </summary>
		public DamageType NormalDamageType
		{
			get { return Get<DamageType>(DamageType.SD, "NormalDamageType"); }
			private set { Set(value, "NormalDamageType"); }
		}


		/// <summary>
		/// This is calculated from PS/PS Type based on the type of attack
		/// </summary>
		public string PowerDamageBase
		{
			get { return Get<String>("PowerDamageBase"); }
			private set { Set(value, "PowerDamageBase"); }
		}

		/// <summary>
		/// This is calculated from PS/PS Type based on the type of attack
		/// </summary>
		public DamageType PowerDamageType
		{
			get { return Get<DamageType>(DamageType.SD, "PowerDamageType"); }
			private set { Set(value, "PowerDamageType"); }
		}



		[CalculatedField("RestrainedDamageBase,DamageFromPS,RestrainedDamageType")]
		public string RestrainedDamage
		{
			get
			{
				var damageType = (OverrideDamageType ?? RestrainedDamageType);
				string result = "";

				//Only add damages together if they are of the same type
				if (damageType == RestrainedDamageType)
					result += RestrainedDamageBase;

				if (!String.IsNullOrEmpty(DamageBase))
				{
					if (String.IsNullOrEmpty(result))
						result = DamageBase;
					else
						result += "+" + DamageBase;
				}

				if (String.IsNullOrEmpty(result))
					return "";

				if (DamageFromPS != 0 && damageType == DamageType.SD)
					result += DamageFromPS.ToString("+0;-0");

				result += " " + damageType;
				return result;
			}
		}

		[CalculatedField("NormalDamageBase,DamageFromPS,NormalDamageType,DamageBase")]
		public string NormalDamage
		{
			get
			{
				var damageType = (OverrideDamageType ?? NormalDamageType);
				string result = "";

				//Only add damages together if they are of the same type
				if (damageType == NormalDamageType)
					result += NormalDamageBase;

				if (!String.IsNullOrEmpty(DamageBase))
				{
					if (String.IsNullOrEmpty(result))
						result = DamageBase;
					else
						result += "+" + DamageBase;
				}

				if (String.IsNullOrEmpty(result))
					return "";

				if (DamageFromPS != 0 && damageType == DamageType.SD)
					result += DamageFromPS.ToString("+0;-0");

				result += " " + damageType;
				return result;
			}
		}

		[CalculatedField("PowerDamageBase,DamageFromPS,PowerDamageType")]
		public string PowerDamage
		{
			get
			{
				var damageType = (OverrideDamageType ?? PowerDamageType);

				if (string.IsNullOrEmpty(PowerDamageBase))
					return "";

				if (PowerDamageBase != "x2")
				{
					var result = "";

					//Only add damages together if they are of the same type
					if (damageType == NormalDamageType)
						result += PowerDamageBase;

					if (!String.IsNullOrEmpty(DamageBase))
					{
						if (String.IsNullOrEmpty(result))
							result = DamageBase;
						else
							result += "+" + DamageBase;
					}

					if (DamageFromPS != 0 && damageType == DamageType.SD)
						result += DamageFromPS.ToString("+0;-0");

					result += " " + damageType;

					return result;
				}
				else
					return PowerDamageBase;
				
			}
		}


		public int DamageFromPS
		{
			get { return Get<int>("DamageFromPS"); }
			private set { Set(value, "DamageFromPS"); }
		}

		public void Recalculate(int ps, int damageFromPS, PSType psType, bool hasPowerPunch, bool hasPowerKick, int meleeStrike, int rangedStrike)
		{
			switch (WeaponType)
			{
				case WeaponType.Ranged:
					StrikeBase = rangedStrike;
					break;
				case Characters.WeaponType.Melee:
					StrikeBase = meleeStrike;
					break;

				default:
					StrikeBase = null;
					break;
			}

			bool hasPower = false;
			var isKick = false;
			var isLeapKick = false;
			var isPunch = false;

			switch (BasedOn ?? Name)
			{
				case "Backhand":
					NormalDamageBase = "1D4";
					isPunch = true;
					hasPower = hasPowerPunch;
					break;

				case "Body Flip/Throw":
					NormalDamageBase = "1D6";
					PowerDamageBase = "x2";
					isPunch = true;
					hasPower = hasPowerPunch;
					break;

				case "Punch":
					NormalDamageBase = "1D4";
					isPunch = true;
					hasPower = hasPowerPunch;
					break;

				case "Karate Punch":
					NormalDamageBase = "2D4";
					isPunch = true;
					hasPower = hasPowerPunch;
					break;

				case "Elbow Strike":
					NormalDamageBase = "2D4";
					isPunch = true;
					hasPower = false;

					break;

				case "Kick":
					NormalDamageBase = "1D8";
					isKick = true;
					hasPower = hasPowerKick;
					break;

				case "Karate Kick":
					NormalDamageBase = "2D6";
					isKick = true;
					hasPower = hasPowerKick;
					break;

				case "Leap Kick":
					NormalDamageBase = "3D8";
					isKick = true;
					isLeapKick = true;
					hasPower = false;
					break;

				case "Knee Strike":
					NormalDamageBase = "1D6";
					isKick = true;
					hasPower = false;
					break;

				//case "PS":
				//	DamageFromPS = damageFromPS;
				//	break;

				default:
					return; //this isn't a pre-defined type so don't mess with it
			}

			//reset calculated fields
			RestrainedDamageBase = null;
			RestrainedDamageType = Characters.DamageType.SD;
			NormalDamageType = Characters.DamageType.SD;
			PowerDamageType = Characters.DamageType.SD;
			DamageFromPS = psType == PSType.Normal ? damageFromPS : 0;

			//default damage bonus from power attacks
			if (hasPower)
				PowerDamageBase = "x2";
			else
				PowerDamageBase = null;




			//apply supernatural bonsues
			if (psType == PSType.Augmented)
			{
				if (ps < 24)
				{
					//no-op
				}
				else if (ps == 24 && hasPower)
				{
					PowerDamageBase = "1";
					PowerDamageType = DamageType.MD;
				}
				else if (ps >= 25 && ps <= 27 && hasPower)
				{
					PowerDamageBase = "1D4";
					PowerDamageType = DamageType.MD;
				}
				else if (ps >= 28 && ps <= 30 && hasPower)
				{
					PowerDamageBase = "1D6";
					PowerDamageType = DamageType.MD;
				}
				else if (ps >= 31 && ps <= 40 && hasPower)
				{
					PowerDamageBase = "2D4";
					PowerDamageType = DamageType.MD;
				}
				else if (ps >= 41 && ps <= 50)
				{
					if (isPunch)
					{
						RestrainedDamageBase = "3D6";
						NormalDamageBase = "1D4";
						NormalDamageType = DamageType.MD;
					}
					if (hasPower)
					{
						PowerDamageBase = "3D4";
						PowerDamageType = DamageType.MD;
					}
				}
				else if (ps >= 51)
				{
					if (isPunch)
					{
						RestrainedDamageBase = "4D6";
						NormalDamageBase = "1D8";
						NormalDamageType = DamageType.MD;
					}
					if (hasPower)
					{
						PowerDamageBase = "4D4";
						PowerDamageType = DamageType.MD;
					}
				}
			}
			else if (psType == PSType.Robot)
			{
				if (ps <= 15)
				{
					if (isPunch)
					{
						RestrainedDamageBase = "1D6";
						NormalDamageBase = "2D6";
						if (hasPower)
							PowerDamageBase = "4D6";
					}
					else if (isLeapKick)
					{
						NormalDamageBase = "3D6";
					}
					else if (isKick)
					{
						NormalDamageBase = "2D6";
					}
				}
				else if (ps >= 16 && ps <= 20)
				{
					if (isPunch)
					{
						RestrainedDamageBase = "2D6";
						NormalDamageBase = "1";
						NormalDamageType = DamageType.MD;
						if (hasPower)
						{
							PowerDamageBase = "1D6";
							PowerDamageType = DamageType.MD;
						}
					}
					else if (isKick)
					{
						NormalDamageBase = !isLeapKick ? "1D4" : "2D4";
						NormalDamageType = DamageType.MD;
						PowerDamageType = DamageType.MD;
					}
				}
				else if (ps >= 21 && ps <= 25)
				{
					if (isPunch)
					{
						RestrainedDamageBase = "6D6";
						NormalDamageBase = "1D4";
						NormalDamageType = DamageType.MD;
						if (hasPower)
						{
							PowerDamageBase = "2D4";
							PowerDamageType = DamageType.MD;
						}
					}
					else if (isKick)
					{
						NormalDamageBase = !isLeapKick ? "1D6" : "2D6";
						NormalDamageType = DamageType.MD;
						PowerDamageType = DamageType.MD;
					}
				}
				else if (ps >= 26 && ps <= 30)
				{
					if (isPunch)
					{
						RestrainedDamageBase = "1D4";
						RestrainedDamageType = DamageType.MD;
						NormalDamageBase = "1D6";
						NormalDamageType = DamageType.MD;
						if (hasPower)
						{
							PowerDamageBase = "2D6";
							PowerDamageType = DamageType.MD;
						}
					}
					else if (isKick)
					{
						NormalDamageBase = !isLeapKick ? "2D4" : "2D8";
						NormalDamageType = DamageType.MD;
						PowerDamageType = DamageType.MD;
					}
				}
				else if (ps >= 31 && ps <= 35)
				{
					if (isPunch)
					{
						RestrainedDamageBase = "1D4";
						RestrainedDamageType = DamageType.MD;
						NormalDamageBase = "2D4";
						NormalDamageType = DamageType.MD;
						if (hasPower)
						{
							PowerDamageBase = "4D4";
							PowerDamageType = DamageType.MD;
						}
					}
					else if (isKick)
					{
						NormalDamageBase = !isLeapKick ? "3D8" : "5D8";
						NormalDamageType = DamageType.MD;
						PowerDamageType = DamageType.MD;
					}
				}
				else if (ps >= 36 && ps <= 40)
				{
					if (isPunch)
					{
						RestrainedDamageBase = "1D4";
						RestrainedDamageType = DamageType.MD;
						NormalDamageBase = "2D6";
						NormalDamageType = DamageType.MD;
						if (hasPower)
						{
							PowerDamageBase = "4D6";
							PowerDamageType = DamageType.MD;
						}
					}
					else if (isKick)
					{
						NormalDamageBase = !isLeapKick ? "3D8" : "5D8";
						NormalDamageType = DamageType.MD;
						PowerDamageType = DamageType.MD;
					}
				}
				else if (ps >= 41 && ps <= 50)
				{
					if (isPunch)
					{
						RestrainedDamageBase = "1D6";
						RestrainedDamageType = DamageType.MD;
						NormalDamageBase = "3D6";
						NormalDamageType = DamageType.MD;
						if (hasPower)
						{
							PowerDamageBase = "1D6x10";
							PowerDamageType = DamageType.MD;
						}
					}
					else if (isKick)
					{
						NormalDamageBase = !isLeapKick ? "5D8" : "1D8x10";
						NormalDamageType = DamageType.MD;
						PowerDamageType = DamageType.MD;
					}
				}
				else if (ps >= 51 && ps <= 60)
				{
					if (isPunch)
					{
						RestrainedDamageBase = "2D6";
						RestrainedDamageType = DamageType.MD;
						NormalDamageBase = "6D6";
						NormalDamageType = DamageType.MD;
						if (hasPower)
						{
							PowerDamageBase = "2D6x10";
							PowerDamageType = DamageType.MD;
						}
					}
					else if (isKick)
					{
						NormalDamageBase = !isLeapKick ? "6D8" : "2D6x10";
						NormalDamageType = DamageType.MD;
						PowerDamageType = DamageType.MD;
					}
				}

			}
			else if (psType == PSType.Supernatural)
			{
				//punches and kicks are treated as being equal
				if (ps <= 15)
				{
					RestrainedDamageBase = "1D6";
					NormalDamageBase = "4D6";
					if (hasPower)
					{
						PowerDamageBase = "1D4";
						PowerDamageType = DamageType.MD;
					}
				}
				else if (ps >= 16 && ps <= 20)
				{
					RestrainedDamageBase = "3D6";
					NormalDamageBase = "1D6";
					NormalDamageType = DamageType.MD;
					if (hasPower)
					{
						PowerDamageBase = "2D6";
						PowerDamageType = DamageType.MD;
					}
				}
				else if (ps >= 21 && ps <= 25)
				{
					RestrainedDamageBase = "4D6";
					NormalDamageBase = "2D6";
					NormalDamageType = DamageType.MD;
					if (hasPower)
					{
						PowerDamageBase = "4D6";
						PowerDamageType = DamageType.MD;
					}
				}
				else if (ps >= 26 && ps <= 30)
				{
					RestrainedDamageBase = "5D6";
					NormalDamageBase = "3D6";
					NormalDamageType = DamageType.MD;
					if (hasPower)
					{
						PowerDamageBase = "6D6";
						PowerDamageType = DamageType.MD;
					}
				}
				else if (ps >= 31 && ps <= 35)
				{
					RestrainedDamageBase = "5D6";
					NormalDamageBase = "4D6";
					NormalDamageType = DamageType.MD;
					if (hasPower)
					{
						PowerDamageBase = "1D4x10";
						PowerDamageType = DamageType.MD;
					}
				}
				else if (ps >= 36 && ps <= 40)
				{
					RestrainedDamageBase = "6D6";
					NormalDamageBase = "5D6";
					NormalDamageType = DamageType.MD;
					if (hasPower)
					{
						PowerDamageBase = "1D6x10";
						PowerDamageType = DamageType.MD;
					}
				}
				else if (ps >= 41 && ps <= 50)
				{
					RestrainedDamageBase = "1D6x10";
					NormalDamageBase = "6D6";
					NormalDamageType = DamageType.MD;
					if (hasPower)
					{
						PowerDamageBase = "2D4x10";
						PowerDamageType = DamageType.MD;
					}
				}
				else if (ps >= 51 && ps <= 60)
				{
					RestrainedDamageBase = "1D6";
					RestrainedDamageType = DamageType.SD;
					NormalDamageBase = "1D6x10";
					NormalDamageType = DamageType.MD;
					if (hasPower)
					{
						PowerDamageBase = "2D6x10";
						PowerDamageType = DamageType.MD;
					}
				}
			}



		}
	}
}
